"""
辅助函数模块，包含坐标转换等工具。
"""

import math
import sys
import os
from pathlib import Path

# 瓦片大小 (像素)
TILE_SIZE = 256


def lonlat_to_tile(lon: float, lat: float, zoom: int) -> tuple[int, int]:
    """
    将 WGS84 经纬度坐标转换为瓦片坐标 (x, y)。

    Args:
        lon (float): 经度。
        lat (float): 纬度。
        zoom (int): 缩放级别。

    Returns:
        tuple[int, int]: 对应的瓦片坐标 (x, y)。
    """
    lat_rad = math.radians(lat)
    n = 2.0 ** zoom
    x_tile = int((lon + 180.0) / 360.0 * n)
    y_tile = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n)
    return x_tile, y_tile


def tile_to_lonlat(x: int, y: int, zoom: int) -> tuple[float, float]:
    """
    将瓦片坐标 (x, y) 转换为左上角的 WGS84 经纬度坐标。

    Args:
        x (int): 瓦片 x 坐标。
        y (int): 瓦片 y 坐标。
        zoom (int): 缩放级别。

    Returns:
        tuple[float, float]: 对应的经纬度坐标 (lon, lat)。
    """
    n = 2.0 ** zoom
    lon_deg = x / n * 360.0 - 180.0
    lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * y / n)))
    lat_deg = math.degrees(lat_rad)
    return lon_deg, lat_deg


# --- 全球瓦片范围计算 ---
def get_global_tile_range(zoom: int) -> tuple[int, int, int, int]:
    """
    计算指定缩放级别下全球范围的瓦片坐标。

    Args:
        zoom (int): 缩放级别。

    Returns:
        tuple[int, int, int, int]: 瓦片范围 (min_x, min_y, max_x, max_y)。
                                   通常为 (0, 0, 2^zoom - 1, 2^zoom - 1)。
    """
    max_tile = 2 ** zoom - 1
    return (0, 0, max_tile, max_tile)


def get_resource_path(relative_path):
    """获取资源文件在打包后或开发时的绝对路径。"""
    try:
        # PyInstaller 创建的临时文件夹路径
        base_path = sys._MEIPASS
    except Exception:
        # 正常 Python 环境
        base_path = Path(__file__).parent  # 或 os.path.abspath(os.path.dirname(__file__))
    # 返回最终的资源路径
    return os.path.join(base_path, relative_path)


def tile_bounds_to_pixels(tile_x: int, tile_y: int, zoom: int,
                          lon_min: float, lat_min: float, lon_max: float, lat_max: float) -> tuple[int, int, int, int]:
    """
    计算在指定缩放级别下，一个瓦片内部需要保留的像素区域 (left, top, right, bottom)，
    该区域对应于给定的经纬度范围 [lon_min, lat_min, lon_max, lat_max]。

    Args:
        tile_x (int): 瓦片的 X 坐标。
        tile_y (int): 瓦片的 Y 坐标。
        zoom (int): 缩放级别。
        lon_min (float): 目标区域的最小经度。
        lat_min (float): 目标区域的最小纬度。
        lon_max (float): 目标区域的最大经度。
        lat_max (float): 目标区域的最大纬度。

    Returns:
        tuple[int, int, int, int]: 瓦片内需要保留的像素区域 (left, top, right, bottom)。
                                   如果区域完全在瓦片外，则可能返回无效范围 (left >= right or top >= bottom)。
    """

    # 1. 计算当前瓦片的四个角的经纬度
    tile_lon_min, tile_lat_max = tile_to_lonlat(tile_x, tile_y, zoom)  # 左上角
    tile_lon_max, tile_lat_min = tile_to_lonlat(tile_x + 1, tile_y + 1, zoom)  # 右下角

    # 2. 计算目标区域与当前瓦片在经度和纬度上的重叠部分
    # 交集的经纬度范围
    intersect_lon_min = max(tile_lon_min, lon_min)
    intersect_lon_max = min(tile_lon_max, lon_max)
    intersect_lat_min = max(tile_lat_min, lat_min)
    intersect_lat_max = min(tile_lat_max, lat_max)

    # 3. 如果没有交集，则返回一个无效区域
    if (intersect_lon_min >= intersect_lon_max or
            intersect_lat_min >= intersect_lat_max):
        # 没有重叠，返回无效像素范围
        return (0, 0, 0, 0)

        # 4. 将交集的经纬度范围转换回当前瓦片的像素坐标
    # 需要计算交集范围在当前瓦片坐标系中的相对位置

    # 瓦片左上角的经纬度
    tile_left_lon, tile_top_lat = tile_lon_min, tile_lat_max

    # 经纬度到像素的转换 (假设线性插值，对于 Web Mercator 投影是近似的)
    # 经度 -> X 像素
    lon_range = tile_lon_max - tile_lon_min
    pixel_x_min = int(((intersect_lon_min - tile_left_lon) / lon_range) * TILE_SIZE)
    pixel_x_max = int(((intersect_lon_max - tile_left_lon) / lon_range) * TILE_SIZE)

    # 纬度 -> Y 像素 (注意：Y 轴在图像中向下为正，而纬度向上为正)
    lat_range = tile_lat_max - tile_lat_min
    # intersect_lat_max 对应 tile 的上边 (像素 Y 小)
    pixel_y_min = int(((tile_top_lat - intersect_lat_max) / lat_range) * TILE_SIZE)
    # intersect_lat_min 对应 tile 的下边 (像素 Y 大)
    pixel_y_max = int(((tile_top_lat - intersect_lat_min) / lat_range) * TILE_SIZE)

    # 确保像素坐标在有效范围内
    pixel_x_min = max(0, min(TILE_SIZE, pixel_x_min))
    pixel_x_max = max(0, min(TILE_SIZE, pixel_x_max))
    pixel_y_min = max(0, min(TILE_SIZE, pixel_y_min))
    pixel_y_max = max(0, min(TILE_SIZE, pixel_y_max))

    # 返回 (left, top, right, bottom) 格式
    return (pixel_x_min, pixel_y_min, pixel_x_max, pixel_y_max)
